Skip to content

Background Maia + Stockfish analysis during drill play#260

Merged
ashtonanderson merged 9 commits into
mainfrom
codex/drill-background-analysis
Mar 27, 2026
Merged

Background Maia + Stockfish analysis during drill play#260
ashtonanderson merged 9 commits into
mainfrom
codex/drill-background-analysis

Conversation

@ashtonanderson
Copy link
Copy Markdown
Member

Summary

  • Background analysis during drills: While the player is actively playing a drill, Maia and Stockfish analysis runs in the background on all positions in the drill's main line. This means post-drill analysis is faster or instant since most positions are already analyzed.
  • Promise-chain pattern: Background analysis uses a sequential promise chain (bgChainRef) to avoid clobbering the single Stockfish WASM instance. Each node is analyzed one at a time (Maia first, then Stockfish).
  • Disable engine analysis during drill play: Added an enabled flag to useEngineAnalysis so the analysis controller doesn't auto-fire Stockfish on every board position change during drills, which would steal the engine from background analysis.

Key changes

  • useOpeningDrillController.ts — Background analysis lifecycle (enqueue, cancel on drill change, stop on drill end)
  • useEngineAnalysis.ts — Added enabled parameter to gate Maia/Stockfish effects
  • useAnalysisController.ts — Passes enableEngineAnalysis flag through
  • openings/index.tsx — Disables engine analysis during drill play, only syncs nodes when analysis is active

Test plan

  • Start a drill and verify console logs show background Maia + Stockfish analysis progressing through positions
  • Complete a drill and verify the post-drill analysis modal loads faster (positions already analyzed show immediately)
  • Verify post-drill analysis still works correctly for any positions not yet reached by background analysis
  • Verify switching drills mid-play cancels background analysis and starts fresh
  • Verify normal (non-drill) analysis page still works as before

🤖 Generated with Claude Code

ashtonanderson and others added 9 commits March 27, 2026 00:04
The previous implementation used a useEffect cleanup to cancel the
background Stockfish/Maia analysis loop on every dependency change
(including every new move). This killed evaluations mid-stream and
marked nodes as queued without completing them. Replaced with a
ref-based queue and persistent async loop that only cancels when
the drill session itself changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: currentDrillGame state changes on every player/Maia move
(updating moves array and playerMoveCount). The cancellation effect
depended on currentDrillGame, so every move triggered cleanup which
set backgroundCancelledRef=true, killing the loop immediately.

Fix: track drill identity by ID instead of the full state object.
Only cancel when a genuinely new drill starts. Also stop background
analysis when post-drill analysis begins to avoid stockfish contention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Background loop runs both Maia + Stockfish on drill positions as
they're played. When the drill ends, ensureDrillAnalysis:
1. Sets cancelled flag (loop exits after current position)
2. Calls stockfish.stopEvaluation() to abort any in-progress eval
3. Awaits the loop promise to ensure full exit
4. Only then starts its own stockfish work

This avoids the concurrent generator bug where the old generator's
finally block would clobber the new generator's engine.listen
callback, causing the post-drill analysis to hang.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
React runs useEffects in declaration order. The separate cancellation
effect was firing AFTER the enqueue effect, clearing the queue that
was just populated. Merged both into a single effect so drill-change
reset and node enqueuing happen atomically.

Also handle drill-cleared case (cancel background when no active drill).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detailed [bg] logs at each stage to diagnose why background analysis
doesn't run during drill play.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The queue/loop pattern had too many failure modes (running flags,
queue clearing, effect ordering). Replaced with a simple promise
chain: each new drill node gets its analysis chained onto a single
ref promise. No queue, no running flag, no separate loop callback.

- bgChainRef: single promise chain, analysis tasks appended via .then()
- bgAnalyzedFensRef: Set tracks which FENs have been scheduled
- Drill change: cancel flag + chain reset
- stopBackgroundAnalysis: sets cancel + stops stockfish + awaits chain

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two fixes:
1. Wrap each chain step in try/catch so a single error doesn't reject
   the entire promise chain
2. Don't await the chain when stopping — just signal cancellation and
   stop stockfish, then proceed. Awaiting was hanging when a step was
   stuck (e.g., Maia ONNX inference or stockfish generator)

Also added more detailed [bg] console logs at each stage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: useAnalysisController's useEngineAnalysis hook auto-runs
stockfish on every currentNode change. During drill play, each move
synced the node to the analysis controller, which called
stockfish.streamEvaluations() — killing the background analysis's
in-progress evaluation (the new call's stopEvaluation() terminates
the old generator).

Fix: only sync currentNode to the analysis controller when analysis
is actually active (post-drill continue-analyzing mode), not during
active drill play.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The analysis controller's useEngineAnalysis hook has its own internal
tree controller that navigates the drill's game tree. Even though we
stopped syncing currentNode, the internal controller still tracked
tree changes and fired stockfish.streamEvaluations() — which calls
stopEvaluation() and kills the background analysis's in-progress
evaluation (explaining depth 8 instead of 18).

Added an 'enabled' parameter to useEngineAnalysis and
useAnalysisController. During drill play (analysisEnabled=false,
continueAnalyzingMode=false), both Maia and Stockfish effects in
useEngineAnalysis are completely skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
maia-platform-frontend Ready Ready Preview, Comment Mar 27, 2026 4:08am

Request Review

@ashtonanderson ashtonanderson merged commit 611c2cc into main Mar 27, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant